//
// Created by hanshu on 2020/8/1.
//

#ifndef PROJ_ANDROID_BLUETOOTHHELPER_H
#define PROJ_ANDROID_BLUETOOTHHELPER_H

#include <jni.h>
#include <string>
#include <atomic>

#define  LOG_TAG    "bttt-c++"
#define  LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)

#include "renderer/CCRenderer.h"
#include "renderer/CCCustomCommand.h"
#include "base/CCDirector.h"
#include "base/CCEventType.h"
#include "base/CCConfiguration.h"
#include "base/CCEventDispatcher.h"

#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
#include "platform/android/jni/JniHelper.h"

#include "../cocos2d/cocos/platform/android/jni/JniHelper.h"
#include "../cocos2d/cocos/scripting/deprecated/CCDeprecated.h"

#include "ActCmd.h"
#include "HelloWorldScene.h"

#include "NDK_CPP_Utils.h"

#endif

//using namespace std;
USING_NS_CC;
USING_NS_CC_EXT;

struct _oneRecvBuf
{
    unsigned char buf[64];
    unsigned short len;
};


#define IS_VAIL_SEG(b0,b1) b0 == 0xfd &&(b1 == 0xfd || b1 == 0xfe)
#define GET_ONE_COORD(b0,b1) (b0 & 0xff) |((b1 & 0xff)<<8)// 最低位

class BlueToothHelperDelegate
{
public:
    virtual void setNotifyLabel(std::string) = 0;
    virtual void setOneAct(ActCmd &) = 0;
    virtual void setKeyAct(ControlCode &) = 0;
};

class BlueToothHelper {
public:
    static PenStatus last_penStatus;
    static int connectDeviceType;
    static float last_penX;
    static float last_penY;
    constexpr static const float penPointH = 14800;
    constexpr static const float penPointW = 21000;

    static std::string connectBleMacId;
    static BlueToothHelperDelegate * notifyTarget;

    static void parseBtB5Raw(int penState,float coordX,float coordY,float coordForce)
    {
        float x = coordY / penPointH;
        float y = (penPointW - coordX) / penPointW;

        //0 = hover / 1 down / 2 move / 3 up / 4 = leaving
        last_penStatus = PenStatus_NOTHING;
        if(penState == 0){
            last_penStatus = PenStatus_Hover;
        }
        if(penState == 1){
            last_penStatus = PenStatus_Down;
        }
        if(penState == 2){
            last_penStatus = PenStatus_Move;
        }
        if(penState == 3){
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               last_penStatus = PenStatus_Up;
        }
        if(penState == 4){
            last_penStatus = PenStatus_Leave ;
        }

        ActCmd oneAct;
        oneAct.act = Pen_Write;
        oneAct.x = x;
        oneAct.y = y;
        oneAct.presure = coordForce / 8193.0;
        oneAct.actDetail = last_penStatus;

        if(BlueToothHelper::notifyTarget != nullptr) {
            BlueToothHelper::notifyTarget->setOneAct(oneAct);
        }
    }

    static void parseHSDRaw(int penState,float coordX,float coordY,float coordForce,float strokeNum,std::string &pageAddrJava)
    {
        last_penStatus = PenStatus_Move;
        if(penState == 1) {
            last_penStatus = PenStatus_Down;
        }

        if(penState == 3) {
            last_penStatus = PenStatus_Up;
        }

        if(penState == 4){
            last_penStatus = PenStatus_Hover;
        }

        ActCmd oneAct;
        oneAct.act = Pen_Write;
        oneAct.x = coordX;
        oneAct.y = coordY;
        oneAct.presure = coordForce;
        oneAct.actDetail = last_penStatus;

        if(BlueToothHelper::notifyTarget != nullptr) {
            BlueToothHelper::notifyTarget->setOneAct(oneAct);
        }
    }

    static void parseByRaw(_oneRecvBuf &oneBuf){
        if (oneBuf.len > 0) {
            int num = oneBuf.len;
            int index = 0;
            while (index + 10 <= num) {
                //IS_VAIL_SEG(b0,b1) b0 == 0xfd &&(b1 == 0xfd || b1 == 0xfe)
                if(IS_VAIL_SEG(oneBuf.buf[index],oneBuf.buf[index+1])){
                    bool flag = false;
                    if (index + 10 == num) {
                        flag = true;
                    } else if (index + 12 <= num) {
                        if (IS_VAIL_SEG(oneBuf.buf[index+10],oneBuf.buf[index+11])){
                            //this.byteToInt(data[index + 10], data[index + 11]) == 0xfdfd || this.byteToInt1(data[index + 10], data[index + 11]) == 0xfdfe) {
                            flag = true;
                        }
                    }
                    if (flag) {
                        long type = (oneBuf.buf[index + 2] & 0xFF);
                        long mode = (oneBuf.buf[index + 3] & 0xFF);
                        float bleX = GET_ONE_COORD(oneBuf.buf[index + 4], oneBuf.buf[index + 5]);
                        float bleY = GET_ONE_COORD(oneBuf.buf[index + 6], oneBuf.buf[index + 7]);
                        long key = -1;

                        //软件按钮
                        // console.log("buttonLog", "btnIndex:" + bleX);
                        long keyIndex = GET_ONE_COORD(oneBuf.buf[index + 5], oneBuf.buf[index + 6]);
                        //压感
                        long blePressure = GET_ONE_COORD(oneBuf.buf[index + 8], oneBuf.buf[index + 9]);
                        index += 10;
                        if (mode == 0xa1 || (mode == 0x1 && type == 2)) {
                            if (last_penStatus == PenStatus_Hover || last_penStatus == PenStatus_Leave) {
                                last_penStatus = PenStatus_Down;
                                //console.log("AcionLog", "XYPenStatus_Down");
                            } else {
                                last_penStatus = PenStatus_Move;
                            }
                        } else if (mode == 0xa0 || (mode == 0x2 && type == 2)) {
                            if (last_penStatus == PenStatus_Down || last_penStatus == PenStatus_Move) {
                                last_penStatus = PenStatus_Up;
                                //console.log("AcionLog", "XYPenStatus_Move");
                            } else {
                                last_penStatus = PenStatus_Hover;
                            }
                        } else if (mode == 0xc0 || (mode == 0x0 && type == 2)) {
                            if (last_penStatus == PenStatus_Down || last_penStatus == PenStatus_Move) {
                                last_penStatus = PenStatus_Up;
                                // console.log("AcionLog", "XYPenStatus_up");
                            } else {
                                last_penStatus = PenStatus_Leave;
                            }
                        }

                        ActCmd oneAct;
                        oneAct.actDetail = PenStatus_NOTHING;
                        switch(keyIndex){
                            case 101://save
                                //this.cleardraw()
                                oneAct.actDetail = PenStatus_SAVE;
                                break;
                            case 102://clean
                                //this.cleardraw()
                                oneAct.actDetail = PenStatus_CLEAR;
                                break;
                            case 103://blue color choose
                                //context.setStrokeStyle('#0000F5');
                                oneAct.actDetail = PenStatus_BLUE;
                                break;
                            case 104://black color choose
                                //context.setStrokeStyle('#000000');
                                oneAct.actDetail = PenStatus_BLACK;
                                break;
                            case 105://red color choose
                                //context.setStrokeStyle('#FF0000');
                                oneAct.actDetail = PenStatus_RED;
                                break;
                            case 106://笔记细
                                oneAct.actDetail = PenStatus_PEN_FINE;
                                break;
                            case 107://笔记中
                                oneAct.actDetail = PenStatus_PEN_MEDIUM;
                                break;
                            case 108://笔记粗
                                oneAct.actDetail = PenStatus_PEN_BOLD;
                                break;
                            case 109://画笔选择
                                oneAct.actDetail = PenStatus_PEN_CHOOSE;
                                break;
                            case 110://画笔选择
                                oneAct.actDetail = PenStatus_MOUSE_CHOOSE;
                                break;
                            case 111://下一页
                                oneAct.actDetail = PenStatus_NEXT;
                                break;
                            case 112://上一页
                                oneAct.actDetail = PenStatus_PREV;
                                break;
                        }

                        oneAct.act = Pen_DONOTHING;
                        if(oneAct.actDetail != PenStatus_NOTHING){
                            oneAct.act = Pen_Ctl;
                        }else {
/*
                            last_penX = bleX;
                            last_penY = bleY;
                            float y = (penPointW - bleX) / penPointW;
                            float x = bleY / penPointH;
                            if(isLand){
                                x = (penPointH - bleX) / penPointH;
                                y = bleY / penPointW;

                                float mm = x;

                                if (!isTopPos){
                                    x = 1 - y;
                                    y = 1 - mm;
                                }else{
                                    x = y;
                                    y = mm;
                                }
                            }else{
                                if (!isTopPos) {
                                    y = 1 - y;
                                }
                            }

*/
                            last_penX = bleX;
                            last_penY = bleY;
                            float x = bleY / penPointH;
                            float y = (penPointW - bleX) / penPointW;

                            if (y > 0 &&
                                x > 0
                            ) {
                                oneAct.act = Pen_Write;
                                oneAct.x = x;
                                oneAct.y = y;
                                oneAct.presure = blePressure / 8193.0;
                                oneAct.actDetail = last_penStatus;
                            }
                        }

                        if(oneAct.act != Pen_DONOTHING) {
                            if(BlueToothHelper::notifyTarget != nullptr) {
                                BlueToothHelper::notifyTarget->setOneAct(oneAct);
                            }
                        }
                    } else {
                        index += 2;
                    }
                } else {
                    index += 1;
                }
            }
        }
    }

    static void keyProc(int keyCode)
    {
        ControlCode pressKey = ControlCode(keyCode);
        if(BlueToothHelper::notifyTarget != nullptr) {
            BlueToothHelper::notifyTarget->setKeyAct(pressKey);
        }
    }

    static void disconnectBle()
    {
#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
        //1. 获取activity静态对象
        JniMethodInfo minfo;
        bool isHave = JniHelper::getStaticMethodInfo(minfo,
                                                     "org.cocos2dx.cpp.AppActivity",
                                                     "getMe",
                                                     "()Lorg/cocos2dx/cpp/AppActivity;");
        jobject activityObj;
        if (isHave)
        {
            //，获取java类对象。
            activityObj = minfo.env->CallStaticObjectMethod(minfo.classID, minfo.methodID);
            LOGD("jni: calling org/cocos2dx/cpp/AppActivity/getMe()");

        }else{
            LOGD("jni: org.cocos2dx.cpp.AppActivity.getMe 不存在@连接蓝牙");

        }

        //2.  先停止扫描
        isHave = JniHelper::getMethodInfo(minfo,"org.cocos2dx.cpp.AppActivity","disconnectBle", "()V");

        if (!isHave)
        {
            LOGD("jni: disconnectBle 函数不存在");
        }
        else
        {
            minfo.env->CallVoidMethod(activityObj, minfo.methodID);
            LOGD("jni 关闭BLE连接汉服务");
        }
#endif
    }

    static void stopScanBle()
    {
#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
        //1. 获取activity静态对象
        JniMethodInfo minfo;
        bool isHave = JniHelper::getStaticMethodInfo(minfo,
                                                     "org.cocos2dx.cpp.AppActivity",
                                                     "getMe",
                                                     "()Lorg/cocos2dx/cpp/AppActivity;");
        jobject activityObj;
        if (isHave)
        {
            //，获取java类对象。
            activityObj = minfo.env->CallStaticObjectMethod(minfo.classID, minfo.methodID);
            LOGD("jni: calling org/cocos2dx/cpp/AppActivity/getMe()");

        }else{
            LOGD("jni: org.cocos2dx.cpp.AppActivity.getMe 不存在@连接蓝牙");

        }

        //2.  先停止扫描
        isHave = JniHelper::getMethodInfo(minfo,"org.cocos2dx.cpp.AppActivity","stopScanBle", "()V");

        if (!isHave)
        {
            LOGD("jni: stopScanBle 函数不存在");
        }
        else
        {
            minfo.env->CallVoidMethod(activityObj, minfo.methodID);
            LOGD("jni 关闭扫描");
        }
#endif
    }

    static void ConnectByMacId(const std::string &macId)
    {

#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
            //1. 获取activity静态对象
            JniMethodInfo minfo;
            bool isHave = JniHelper::getStaticMethodInfo(minfo,
                                                         "org.cocos2dx.cpp.AppActivity",
                                                         "getMe",
                                                         "()Lorg/cocos2dx/cpp/AppActivity;");
            jobject activityObj;
            if (isHave)
            {
                //，获取java类对象。
                activityObj = minfo.env->CallStaticObjectMethod(minfo.classID, minfo.methodID);
                LOGD("jni: calling org/cocos2dx/cpp/AppActivity/getMe()");

            }else{
                LOGD("jni: org.cocos2dx.cpp.AppActivity.getMe 不存在@连接蓝牙");

            }

            //2.  先停止扫描
            /*
            isHave = JniHelper::getMethodInfo(minfo,"org.cocos2dx.cpp.AppActivity","stopScanBle", "()V");

            if (!isHave)
            {
                LOGD("jni: stopScanBle 函数不存在");
            }
            else
            {
                minfo.env->CallVoidMethod(activityObj, minfo.methodID);
                LOGD("jni 关闭扫描");
            }
            */

            //3. ，获取其函数信息，    public void connectBLEByMacId(String macId){
            isHave = JniHelper::getMethodInfo(minfo,"org.cocos2dx.cpp.AppActivity","connectBLEByMacId", "(Ljava/lang/String;)V");

            if (!isHave)
            {
                LOGD("jni: connectBLEByMacId 函数不存在");
            }
            else
            {
                //调用displayWebView函数，并传入参数
                jstring jMacId = minfo.env->NewStringUTF(macId.c_str());
                minfo.env->CallVoidMethod(activityObj, minfo.methodID, jMacId);
                LOGD("jni 开始connecting");
            }
#endif
    }
};


#endif //PROJ_ANDROID_BLUETOOTHHELPER_H
